
/** @file multi_index.cc
 *
 * Implementation of multi_index 
 *
 */

/*
 *  Copyright (C) 2003 Stefan Weinzierl
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "multi_index.h"

namespace sector_decomposition {

  // ctors

  /**
   *
   * Default constructor
   *
   */
  basic_multi_index::basic_multi_index(void) : N(0), v(), flag_overflow(false)
    {}

  /**
   *
   * Construct a multi_index with upper limit N and size k .
   *
   */
  basic_multi_index::basic_multi_index(size_t NN, size_t k) : N(NN), v(k), flag_overflow(false)
    {}

  /**
   *
   * Construct from a vector.
   *
   */
  basic_multi_index::basic_multi_index(size_t NN, const std::vector<size_t> & vv) : N(NN), v(vv), flag_overflow(false)
    {}

  // functions 

  /**
   *
   * Returns the size of a multi_index.
   *
   */
  size_t basic_multi_index::size(void) const
    {
      return v.size();
    }

  /**
   *
   * Initialize the multi-index to
   * \f[
   *    (n_1,n_2,n_3,...,n_k) = (0,0,...,0)
   * \f]
   *
   */
  basic_multi_index & basic_multi_index::init(void) 
    {
      flag_overflow = false;

      for ( size_t i=0; i<v.size(); i++)
	{
	  v[i] = 0;
	}
      return *this;
    }

  /**
   *
   * Return the overflow flag.
   *
   */
  bool basic_multi_index::overflow(void) const
    {
      return flag_overflow;
    }

  // subscripting

  /**
   *
   * Subscription via []
   *
   */
  size_t basic_multi_index::operator[](size_t i) const
    {
      return v[i];
    }

  /**
   *
   * Subscription via []
   *
   */
  size_t & basic_multi_index::operator[](size_t i)
    {
      return v[i];
    }

  /**
   *
   * Subscription via ()
   *
   */
  size_t basic_multi_index::operator()(size_t i) const
    {
      return v[i];
    }

  /**
   *
   * Subscription via ()
   *
   */
  size_t & basic_multi_index::operator()(size_t i)
    {
      return v[i];
    }


  /**
   *
   * No effect for basic_multi_index
   *
   */
  basic_multi_index & basic_multi_index::operator++ (int)
    {
      return *this;
    }

  // I/O operators

  /**
   *
   * Output operator. A multi_index prints out as 
   * basic_multi_index(\f$n_0,n_1,...\f$).
   *
   */
  std::ostream & operator<< (std::ostream & os, const basic_multi_index & v)
    {
      os << "basic_multi_index(";
      for ( size_t i=0; i<v.size(); i++)
	{
	  if (i>0) os << ",";
	  os << v(i);
	}

      return os << ")";
    }




  // ctors

  /**
   *
   * Default constructor
   *
   */
  multi_index_ordered::multi_index_ordered(void) : basic_multi_index()
    {}

  /**
   *
   * Construct a multi_index with upper limit N and size k .
   *
   */
  multi_index_ordered::multi_index_ordered(size_t N, size_t k) : basic_multi_index(N,k)
    {}

  /**
   *
   * Construct from a vector.
   *
   */
  multi_index_ordered::multi_index_ordered(size_t N, const std::vector<size_t> & v) : basic_multi_index(N,v)
    {}

  // functions 

  /**
   *
   * Initialize the multi-index to
   * \f[
   *    (n_1,n_2,n_3,...,n_k) = (0,1,2,...,k-1)
   * \f]
   *
   */
  basic_multi_index & multi_index_ordered::init(void) 
    {
      flag_overflow = false;

      for ( size_t i=0; i<v.size(); i++)
	{
	  v[i] = i;
	}
      return *this;
    }

  /**
   *
   * The postfix increment operator allows to
   * write for a multi-index n++, which will
   * update n to the next configuration.
   *
   * If n is in the last configuration and the
   * increment operator ++ is applied to n,
   * the overflow flag will be raised.
   *
   */
  basic_multi_index & multi_index_ordered::operator++ (int)
    {
      int k = this->size();
      int j = k - 1;

      bool exit = false;

      while ( (!exit) && (j>0) )
	{
	  v[j]++;
	  if ( v[j] == (N-k+1+j) )
	    {
	      j--;
	    }
	  else
	    {
	      exit = true;
	    }
	}

      if (j==0)
	{
	  v[j]++;
	  if (v[j] == N-k+1) flag_overflow=true;
	}

      if ( j>= 0)
	{
	  for (int jj=j+1;jj<k;jj++)
	    {
	      v[jj] = v[jj-1]+1;
	    }
	}

      return *this;
    }

  // I/O operators

  /**
   *
   * Output operator. A multi_index_ordered prints out as 
   * multi_index_ordered(\f$n_0,n_1,...\f$).
   *
   */
  std::ostream & operator<< (std::ostream & os, const multi_index_ordered & v)
    {
      os << "multi_index_ordered(";
      for ( size_t i=0; i<v.size(); i++)
	{
	  if (i>0) os << ",";
	  os << v(i);
	}

      return os << ")";
    }

  // ctors

  /**
   *
   * Default constructor
   *
   */
  multi_index_counter::multi_index_counter(void) : basic_multi_index()
    {}

  /**
   *
   * Construct a multi_index with upper limit N and size k .
   *
   */
  multi_index_counter::multi_index_counter(size_t N, size_t k) : basic_multi_index(N,k)
    {}

  /**
   *
   * Construct from a vector.
   *
   */
  multi_index_counter::multi_index_counter(size_t N, const std::vector<size_t> & v) : basic_multi_index(N,v)
    {}

  // functions 

  /**
   *
   * Initialize the multi-index to
   * \f[
   *    (n_1,n_2,n_3,...,n_k) = (0,0,...,0)
   * \f]
   *
   */
  basic_multi_index & multi_index_counter::init(void) 
    {
      flag_overflow = false;

      for ( size_t i=0; i<v.size(); i++)
	{
	  v[i] = 0;
	}
      return *this;
    }

  /**
   *
   * The postfix increment operator allows to
   * write for a multi-index n++, which will
   * update n to the next configuration.
   *
   * If n is in the last configuration and the
   * increment operator ++ is applied to n,
   * the overflow flag will be raised.
   *
   */
  basic_multi_index & multi_index_counter::operator++ (int)
    {
      int k = this->size();
      int j = k - 1;

      bool exit = false;

      while ( (!exit) && (j>0) )
	{
	  v[j]++;
	  if ( v[j] == N )
	    {
	      v[j] = 0;
	      j--;
	    }
	  else
	    {
	      exit = true;
	    }
	}

      if (j==0)
	{
	  v[j]++;
	  if (v[j] == N) 
	    {
	      v[j] = 0;
	      flag_overflow=true;
	    }
	}

      return *this;
    }

  // I/O operators

  /**
   *
   * Output operator. A multi_index_counter prints out as 
   * multi_index_counter(\f$n_0,n_1,...\f$).
   *
   */
  std::ostream & operator<< (std::ostream & os, const multi_index_counter & v)
    {
      os << "multi_index_counter(";
      for ( size_t i=0; i<v.size(); i++)
	{
	  if (i>0) os << ",";
	  os << v(i);
	}

      return os << ")";
    }

  // ctors

  /**
   *
   * Default constructor
   *
   */
  multi_index_counter_indv::multi_index_counter_indv(void) : basic_multi_index(), Nv()
    {}

  /**
   *
   * Construct a multi_index with upper limit N and size k .
   *
   */
  multi_index_counter_indv::multi_index_counter_indv(const std::vector<size_t> & Nvv, size_t k) : basic_multi_index(0,k), Nv(Nvv)
    {}

  /**
   *
   * Construct from a vector.
   *
   */
  multi_index_counter_indv::multi_index_counter_indv(const std::vector<size_t> & Nvv, const std::vector<size_t> & v) : basic_multi_index(0,v), Nv(Nvv)
    {}

  // functions 

  /**
   *
   * Initialize the multi-index to
   * \f[
   *    (n_1,n_2,n_3,...,n_k) = (0,0,...,0)
   * \f]
   *
   */
  basic_multi_index & multi_index_counter_indv::init(void) 
    {
      flag_overflow = false;

      for ( size_t i=0; i<v.size(); i++)
	{
	  v[i] = 0;
	}
      return *this;
    }

  /**
   *
   * The postfix increment operator allows to
   * write for a multi-index n++, which will
   * update n to the next configuration.
   *
   * If n is in the last configuration and the
   * increment operator ++ is applied to n,
   * the overflow flag will be raised.
   *
   */
  basic_multi_index & multi_index_counter_indv::operator++ (int)
    {
      int k = this->size();
      int j = k - 1;

      bool exit = false;

      while ( (!exit) && (j>0) )
	{
	  v[j]++;
	  if ( v[j] == Nv[j] )
	    {
	      v[j] = 0;
	      j--;
	    }
	  else
	    {
	      exit = true;
	    }
	}

      if (j==0)
	{
	  v[j]++;
	  if (v[j] == Nv[j]) 
	    {
	      v[j] = 0;
	      flag_overflow=true;
	    }
	}

      return *this;
    }

  // I/O operators

  /**
   *
   * Output operator. A multi_index_counter_indv prints out as 
   * multi_index_counter_indv(\f$n_0,n_1,...\f$).
   *
   */
  std::ostream & operator<< (std::ostream & os, const multi_index_counter_indv & v)
    {
      os << "multi_index_counter_indv(";
      for ( size_t i=0; i<v.size(); i++)
	{
	  if (i>0) os << ",";
	  os << v(i);
	}

      return os << ")";
    }

} // namespace sector_decomposition

